﻿namespace Catel.Articles._08___WP7_Camera.Test.ViewModels
{
    using System.Collections.Generic;
    using Data;
    using IoC;
    using MVVM.Services;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using _08___WP7_Camera.Data;
    using _08___WP7_Camera.ViewModels;
    using NavigationService = MVVM.Services.Test.NavigationService;
    using MessageService = MVVM.Services.Test.MessageService;

    [TestClass]
    public class PhotoViewModelTest
    {
        private NavigationService _testNavigationService;
        private MessageService _testMessageService;

        [TestInitialize]
        public void Initialize()
        {
            var serviceLocator = ServiceLocator.Instance;

            if (_testNavigationService == null)
            {
                _testNavigationService = new NavigationService();
                serviceLocator.RegisterInstance<INavigationService>(_testNavigationService);
            }

            if (_testMessageService == null)
            {
                _testMessageService = new MessageService();
                serviceLocator.RegisterInstance<IMessageService>(_testMessageService);
            }
        }

        [TestMethod]
        public void Flick_PreventFlickRightIfNoImagesAtRight()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(1);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(0));

            var flickData = new FlickData(FlickMovement.RightToLeft);
            Assert.IsFalse(vm.Flick.CanExecute(flickData));
        }

        [TestMethod]
        public void Flick_FlickRightAtMiddleImage()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(5);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(3));

            var flickData = new FlickData(FlickMovement.RightToLeft);
            Assert.IsTrue(vm.Flick.CanExecute(flickData));
            vm.Flick.Execute(flickData);
            Assert.AreEqual(typeof(PhotoViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to PhotoView");
            Assert.AreEqual(4, _testNavigationService.LastNavigationParameters["id"]);
        }

        [TestMethod]
        public void Flick_FlickLeftAtMiddleImage()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(5);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(3));

            var flickData = new FlickData(FlickMovement.LeftToRight);
            Assert.IsTrue(vm.Flick.CanExecute(flickData));
            vm.Flick.Execute(flickData);
            Assert.AreEqual(typeof(PhotoViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to PhotoView");
            Assert.AreEqual(2, _testNavigationService.LastNavigationParameters["id"]);
        }

        [TestMethod]
        public void Flick_FlickLeftAtFirstImage()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(1);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(0));

            var flickData = new FlickData(FlickMovement.LeftToRight);
            Assert.IsTrue(vm.Flick.CanExecute(flickData), "Flicking left should be allowed to navigate to the main page");
            vm.Flick.Execute(flickData);
            Assert.AreEqual(typeof(MainPageViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to MainPage");
        }

        [TestMethod]
        public void DeleteImage_Cancel()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(3);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();
            _testMessageService.ExpectedResults.Enqueue(MessageResult.Cancel);

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(2));
            vm.Delete.Execute();

            Assert.AreEqual(3, photoRepository.Photos.Count, "Photo count should not have changed");
            Assert.AreEqual(null, _testNavigationService.LastNavigationUri, "Should have canceled");
            Assert.AreEqual(null, _testNavigationService.LastNavigationParameters, "Should have canceled");
        }

        [TestMethod]
        public void DeleteImage_StillImagesAfterDeleteOfMostRightItem()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(3);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();
            _testMessageService.ExpectedResults.Enqueue(MessageResult.OK);

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(2));
            vm.Delete.Execute();

            // Check if view navigates to image index 1
            Assert.AreEqual(2, photoRepository.Photos.Count, "Photo count should have 1 less");
            Assert.AreEqual(typeof(PhotoViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to PhotoView");
            Assert.AreEqual(1, _testNavigationService.LastNavigationParameters["id"]);
        }

        [TestMethod]
        public void DeleteImage_StillImagesAfterDeleteOfMostLeftItem()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(3);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();
            _testMessageService.ExpectedResults.Enqueue(MessageResult.OK);

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(0));
            vm.Delete.Execute();

            // Check if view navigates to image index 0
            Assert.AreEqual(2, photoRepository.Photos.Count, "Photo count should have 1 less");
            Assert.AreEqual(typeof(PhotoViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to PhotoView");
            Assert.AreEqual(0, _testNavigationService.LastNavigationParameters["id"]);
        }

        [TestMethod]
        public void DeleteImage_StillImagesAfterDeleteOfMiddleItem()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(5);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();
            _testMessageService.ExpectedResults.Enqueue(MessageResult.OK);

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(3));
            vm.Delete.Execute();

            // Check if view navigates to image index 2
            Assert.AreEqual(4, photoRepository.Photos.Count, "Photo count should have 1 less");
            Assert.AreEqual(typeof(PhotoViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to PhotoView");
            Assert.AreEqual(2, _testNavigationService.LastNavigationParameters["id"]);
        }

        [TestMethod]
        public void DeleteImage_NoImagesAfterDelete()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(1);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();
            _testMessageService.ExpectedResults.Enqueue(MessageResult.OK);

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(0));
            vm.Delete.Execute();

            // Check if view navigates to main page
            Assert.AreEqual(0, photoRepository.Photos.Count, "Photo count should have 1 less");
            Assert.AreEqual(typeof(MainPageViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to MainPage");
        }

        [TestMethod]
        public void Camera_Navigating()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(1);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(0));

            Assert.IsTrue(vm.GoToCamera.CanExecute());
            vm.GoToCamera.Execute();
            Assert.AreEqual(typeof(MainPageViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to MainPage");
        }

        [TestMethod]
        public void About_Navigating()
        {
            var serviceLocator = ServiceLocator.Instance;
            var photoRepository = new TestPhotoRepository(1);
            serviceLocator.RegisterInstance<IPhotoRepository>(photoRepository);

            _testNavigationService.ClearLastNavigationInfo();

            var vm = new PhotoViewModel();
            vm.UpdateNavigationContext(CreateNavigationContextWithId(0));

            vm.About.Execute();
            Assert.AreEqual(typeof(AboutViewModel).FullName, _testNavigationService.LastNavigationUri, "Should have navigated to AboutView");
        }

        /// <summary>
        /// Creates the navigation context with the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        private static Dictionary<string, string> CreateNavigationContextWithId(int id)
        {
            var navigationContext = new Dictionary<string, string>();
            navigationContext.Add("id", id.ToString());
            return navigationContext;
        }
    }
}
